﻿
using com.iot.core.annotation;
using com.iot.core.data;
using com.iot.core.data.entity;
using com.iot.core.data.service;
using com.iot.core.exception;
using com.iot.core.infrastructure;
using com.iot.core.manager.id;
using com.iot.core.util;
using Microsoft.Extensions.Primitives;
using MySql.Data.MySqlClient;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Threading;
using com.iot.core.boot;
using Microsoft.EntityFrameworkCore;
using Org.BouncyCastle.Tls.Crypto.Impl;
using com.iot.core.manager.htctl;
using System;
using System.Security.Policy;
using System.Linq;

namespace com.iot.core.manager.auth
{
    public class AuthManager
    {
        [MethodImpl(MethodImplOptions.Synchronized)]
        static AuthManager Create()
        {
            //create NopEngine as engine
            return Singleton<AuthManager>.Instance ?? (Singleton<AuthManager>.Instance = new AuthManager());
        }
        public static AuthManager Current
        {
            get
            {
                if (Singleton<AuthManager>.Instance == null)
                {
                    Create();
                }

                return Singleton<AuthManager>.Instance;
            }
        }



        public HtUserLogin GetSuByToken(string token)
        {
            var htUserLoginMapper = EngineContext.Current.Resolve<IRepository<HtUserLogin>>();
            var m = htUserLoginMapper.GetAll().Where(a => a.Online && a.Token.Equals(token)).FirstOrDefault();
            if (m != null)
            {
                m.Htroles = MyJSON.Parse< List<IdNameDto> >(m.HtroleData);
            }
            return m;
        }
        public string CreatePwd(string ename, string pwd)
        {
            var s = com.iot.core.util.MD5.GetMD5Hash(ename + pwd);
            return s;
        }
        //生成Token
        public string CreateToken(long lgid)
        {
            var s = HtIdManager.Current.NextGuid().ToString();
            return s;
        }

        //用户密码检查
        //返回机构
        public  async Task<List<HtDeptBaseDto>> LoginCheckAsync(LoginUserPwdDto loginInfo)
        {
            loginInfo.Ename = loginInfo.Ename.ToLower();
            var htUserMapper = EngineContext.Current.Resolve<IRepository<HtUser>>();
            var htUserDeptService= EngineContext.Current.Resolve<IHtUserDeptService>();


            var ckPWD = CreatePwd(loginInfo.Ename , loginInfo.Pwd);
             
            var muser =await htUserMapper.GetAll().Where(a => a.Ename==loginInfo.Ename  )
                .FirstOrDefaultAsync();
            if (muser == null)
            {
                throw new MyException("用户不存在");
            }
            if (!muser.Pwd.ToLower().Equals(ckPWD.ToLower()))
            {
                throw new MyException("密码错误");
            }

            var l = await htUserDeptService.GetDeptsAsync(muser.Id);
            return l;
        }

        public async Task<string> LoginAsync(LoginDto mm)
        {
            var loginUserPwdDto = new LoginUserPwdDto { Ename = mm.Ename, Pwd= mm.Pwd };
            var ldept = await LoginCheckAsync(loginUserPwdDto);


            HtDeptBaseDto mdept = null;
            if (ldept.Count == 0)
            {
                throw new MyException("没有机构");
            }
            if (mm.HtdeptId > 0)
            {
                ldept = ldept.Where(a => a.Id == mm.HtdeptId).ToList();
            }
            if (mm.HtplatId > 0)
            {
                ldept = ldept.Where(a => a.HtplatId == mm.HtplatId).ToList();
            }
            if (ldept.Count != 1)
            {
                throw new MyException("请登录机构");
            }
            mdept = ldept[0];


            var htUserMapper = EngineContext.Current.Resolve<IRepository<HtUser>>();
            var muser = htUserMapper.GetAll().Where(a => a.Ename.Equals(mm.Ename)).FirstOrDefault();

            var iotHttpContext= EngineContext.Current.Resolve<MyContext>();
            var su = iotHttpContext.Su;

             
            su.Id = HtIdManager.Current.NextLong();
            su.Token = CreateToken(su.Id);
            su.Name = muser.Name;
            su.CrtUid = muser.Id;
            su.CrtDid = mdept.Id;
            su.HtdeptId = mdept.Id;
            su.HtdeptName = mdept.Name;
            su.HtplatId = mdept.HtplatId;
            su.Online = true;
            su.Loginway = mm.Loginway;

            su.Extra = "";

            su.CrtDt = DateTime.Now;              
            su.EdtDt = DateTime.Now;
            su.LogoutDt= DateTime.Now;

            if (mm.Extra != null && mm.Extra.Count > 0)
            {
                if (mm.Extra.ContainsKey("appver"))
                {
                    su.Appver = mm.Extra["appver"] ?? "";
                }
                if (mm.Extra.ContainsKey("imsi"))
                {
                    su.Imsi = mm.Extra["imsi"] ?? "";
                }
                su.Extra =  MyJSON.ToJSONString(mm.Extra); 
            }
            var log = iotHttpContext.MyLog;
            log.Name = muser.Name;
            log.CrtUid = muser.Id;
            log.CrtDid = mdept.Id;
            log.HtdeptId = mdept.Id;
            log.HtdeptName = mdept.Name;
            log.HtplatId = su.HtplatId;

            var htUserRoleService = EngineContext.Current.Resolve<IHtUserRoleService>();

            var lrole =await  htUserRoleService.GetRolesAsync(muser.Id, mdept.Id );

            su.Htroles = lrole; 
            su.HtroleData=MyJSON.ToJSONString(lrole);

            var DB = htUserMapper.DB;
            DB.Set<HtUserLogin>().Where(a => a.Online == true && a.CrtUid == su.CrtUid && a.Loginway == su.Loginway).ToList()
               .ForEach(mold =>
               {
                   mold.Online = false;
                   mold.LogoutDt = DateTime.Now;
                   mold.LogoutMemo = $"被{su.Ip}踢下线";

               });
            DB.Add(su);

            await DB.SaveChangesAsync();
            //缓存menu
            //缓存url 
            return su.Token ;
        }
        public async Task<int> LogoutSelfAsync(  )
        {
            var htUserLoginMapper = EngineContext.Current.Resolve<IRepository<HtUserLogin>>();
             
            var iotHttpContext = EngineContext.Current.Resolve<MyContext>();
            var su = iotHttpContext.Su;
            var m = htUserLoginMapper.GetById(su.Id);
            if (m == null || m.Online == false)
            {
                return 0;
            }
            m.Online=false;
            m.LogoutMemo = "注销";
            m.LogoutDt = DateTime.Now;
            htUserLoginMapper.Update(m, false);
            var r=await htUserLoginMapper.SaveChagnesAsync();
            return r;
        }
        public async Task<List<TreeViewNode>> GetMenuByHtplatIdAsync(long htplat_Id)
        {
            var htMenuMapper = EngineContext.Current.Resolve<IRepository<HtMenu>>();
            var htPageMapper = EngineContext.Current.Resolve<IRepository<HtPage>>();
            var htPageAuthMapper = EngineContext.Current.Resolve<IRepository<HtPageAuth>>();
            var l = await htMenuMapper.GetAll()
                .Where(a => a.HtplatId.Equals(htplat_Id))
                .ToListAsync();


            List<long> lpageid = null;
            lpageid = l.Where(a => a.HtplatId > 0).Select(a => a.HtpageId)
                .Distinct()
                .ToList();
            var lpageauth = new List<HtPageAuth>();
            var lpage = new List<HtPage>();
            var r = new List<TreeViewNode>();
            if (lpageid.Count() > 0)
            {
                lpage = await htPageMapper.GetAll().
                    Where(a => lpageid.Contains(a.Id)).ToListAsync();
                lpageid = lpage.Select(a => a.Id).ToList();
                if (lpageid.Count() > 0)
                { 
                    lpageauth =await htPageAuthMapper.GetAll()
                        .Where(a => lpageid.Contains(a.HtpageId))
                        .ToListAsync();
                }
            }
            AddChildMenu(r, null, l, lpage, lpageauth);
            return r;
        }
        void AddChildMenu(List<TreeViewNode> r, TreeViewNode tn, List<HtMenu> l,
              List<HtPage> lpage,
              List<HtPageAuth> lpageauth
)
        {
            var htMenuMapper = EngineContext.Current.Resolve<IRepository<HtMenu>>();
            var pid = tn == null ? 0L : tn.Id;
            l.Where(a => a.Pid.Equals(pid))
                .OrderBy(a => a.Sortno)
                .ToList()
                .ForEach(mmenu =>
                {
                    var mpage = lpage.Where(a => a.Id.Equals(mmenu.HtpageId)).FirstOrDefault();
                    if(mpage != null)
                    {
                        var lpageAuth2 = lpageauth.Where(a => a.HtpageId.Equals(mpage.Id)).ToList();
                        var tnc = CreateByPage(mmenu, mpage, lpageAuth2);
                        if (tn != null)
                        {
                            tn.Children.Add(tnc);
                        }
                        else
                        {
                            r.Add(tnc);
                        }
                        AddChildMenu(r, tnc, l, lpage, lpageauth);
                    }
                    else
                    {
                        var tnc = new TreeViewNode();
                        htMenuMapper.EntityToDto(mmenu, tnc);
                        tnc.Obj= mmenu.HtpageId.ToString(); 
                        if (tn != null)
                        {
                            tn.Children.Add(tnc);
                        }
                        else
                        {
                            r.Add(tnc);
                        }
                        AddChildMenu(r, tnc, l, lpage, lpageauth);
                    }
                });
               
        }
        TreeViewNode CreateByPage(HtMenu mmenu, HtPage mpage, List<HtPageAuth> lpageauth)  
        {
            var htMenuMapper = EngineContext.Current.Resolve<IRepository<HtMenu>>();
            var htPageAuthMapper = EngineContext.Current.Resolve<IRepository<HtPageAuth>>();
            var tnc = new TreeViewNode();
            htMenuMapper.EntityToDto(mmenu, tnc);
            tnc.Code = mpage.Code;
            tnc.Name = mpage.Name;
            tnc.Imgurl = mpage.Imgurl; 

            foreach(var m in lpageauth)
            {
                var tnc2 = new TreeViewNode();

                tnc2.Lx= "权限";
                tnc2.Obj = m.Urls;
                htPageAuthMapper.EntityToDto(m, tnc2);
                tnc.Children.Add(tnc2);
            }
            return tnc;
        }


        public async Task<bool> HasUrlAsync(HtUserLogin su, string url)
        {
            if (su.CrtUid.Equals(1000L))
            {
                return true;
            }
            url = url.ToLower();
            var mact = HtCtlManager.Current.GetAction(url);
            if (mact == null)
            {
                return true;
            }
            return await HasUrlAsync(su,mact);
        }
        public async Task<bool> HasUrlAsync(HtUserLogin su, HtCtlActDto mact)
        {
            var htRoleMenuService = EngineContext.Current.Resolve<IHtRoleMenuService>();

            if (su.CrtUid.Equals(1000L))
            {
                return true;
            }
            if (mact.AuthType.Equals(AuthType.None))
            {
                return true;
            }

            if (mact.AuthType.Equals(AuthType.Login))
            {
                return su.CrtUid > 0L;
            }
            if (su.CrtUid == 0)
            {
                return false;
            }

            var rids = su.Htroles.Select(a=>a.Id).ToList();
            var lurls =await htRoleMenuService.GetRolesUrlsAsync(rids);
            var url = mact.FullUrl.ToLower();
            var murl = lurls.Where(a => a.Equals(url)).FirstOrDefault();            
            if (murl != null)
            {
                return true;
            }


            var l2 = new List<string>();
            lurls.ForEach(murl =>
            {
                if (murl.IndexOf(",") > 0)
                {
                    murl.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                   .ToList()
                   .ForEach(murl2 =>
                   {
                       l2.Add(murl2.Trim());
                   });
                }
            });
            if (l2.IndexOf(url) >= 0)
            {
                return true;
            }
            lurls.AddRange(l2);

            var ib = url.LastIndexOf("/");
            url = url.Substring(0, ib) + "/*";
            if (lurls.IndexOf(url) >= 0)
            {
                return true;
            }
            return false;

        }


        #region 获取个人菜单
        public async Task<List<TreeViewNode>> GetMenuAsync()
        {
            var myContext = EngineContext.Current.Resolve<MyContext>();
            var htRoleMenuService = EngineContext.Current.Resolve<IHtRoleMenuService>();
            var su = myContext.Su;
            var rid = su.Htroles.Select(a => a.Id).ToList();
            var lHTMenu_Ids = await htRoleMenuService.GetRolesMenuIdsAsync(rid);
            var l =await GetMenuByHtplatIdAsync(su.HtplatId);
            DealMenu(null, l, lHTMenu_Ids);
            return l;
        }
        void DealMenu(TreeViewNode tnp, List<TreeViewNode> ltn, List<long> lid)
        {
            var l = tnp == null ? ltn : tnp.Children ;
            for (var i = l.Count() - 1; i >= 0; i--)
            {
                var tvn = l[i];
                if (lid.Contains(tvn.Id))
                {
                    DealMenu(tvn, ltn, lid);
                }
                else
                {
                    l.Remove(tvn);
                }
            }
        }

        #endregion
    }

}
